﻿#region "Copyright (C) Lenny Granovsky. 2011-2013"
//    This library provides extended cache capabilities to the ASP.NET applications.
//
//                Copyright (C) Lenny Granovsky. 2011-2013. 
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 2 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
//    This program comes with ABSOLUTELY NO WARRANTY.
//    This is free software, and you are welcome to redistribute it
//    under certain conditions;
#endregion

using System;
using System.Diagnostics;
using System.Configuration;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
using System.Web.Caching;

namespace FlexiCache
{
    /// <summary>
    /// Class provides functionality for out-of-process Cache based on Mongo DB. 
    /// It implements the OutputCacheProvider class. 
    /// </summary>
    /// <remarks>This class is not intended to be used directly.</remarks>
    public abstract class ExternalCacheProviderBase : OutputCacheProvider, IDisposable, IExpirationProvider
    {
        protected IExternalCacheStorageAdapter CacheStorageAdapter;

        /// <summary>
        /// Default constructor.
        /// </summary>
        public ExternalCacheProviderBase(CacheStorageConfigInfo config)
            : base()
        {
            this.CacheStorageAdapter = CacheStorageAdapterFactory.CreateInstance(config);
        }

        public void ConnectionTest()
        {
            this.CacheStorageAdapter.ConnectionTest();
        }

        /// <summary>
        /// Method determines whether a cache entry for specified key exists in the cache.
        /// </summary>
        /// <param name="key">Data key.</param>
        /// <returns>Returns true if the cache contains a cache entry whose key matches key; otherwise, false.</returns>
        /// <remarks>Warning: using this method in addition to Get would decrease performance due to an extra roundtrip to the cache storage. 
        /// Use simple Get and then null comparison for ensuring the cached data existance prior to its use. 
        /// Use the Contains method when actual data is not required by the code, but rather knowledge of data existance only.</remarks>
        public virtual bool Contains(string key)
        {
            return this.CacheStorageAdapter.Contains(key);
        }

        /// <summary>
        /// Method gets a data from the cache using specified key.
        /// </summary>
        /// <param name="key">Data key.</param>
        /// <returns>Returns cached object.</returns>
        public override object Get(string key)
        {
            return this.CacheStorageAdapter.Get(key);
        }

        /// <summary>
        /// Method adds data into the cache with specified key and expiration.
        /// </summary>
        /// <param name="key">Data key.</param>
        /// <param name="entry">Data to cache.</param>
        /// <param name="utcExpiry">Expiration time (UTC).</param>
        /// <returns>Returns cached object.</returns>
        public override object Add(string key, object entry, DateTime utcExpiry)
        {
            return Add(key, entry, utcExpiry, "");
        }

        /// <summary>
        /// Method adds data into the cache with specified key and expiration.
        /// </summary>
        /// <param name="key">Data key.</param>
        /// <param name="entry">Data to cache.</param>
        /// <param name="utcExpiry">Expiration time (UTC).</param>
        /// <param name="sessionId">The Session identifier, optional.</param>
        /// <returns>Returns cached object.</returns>
        protected object Add(string key, object entry, DateTime utcExpiry, string sessionId)
        {
            return Add(key, entry, utcExpiry, sessionId, null);
        }

        /// <summary>
        /// Method adds data into the cache with specified key and expiration.
        /// </summary>
        /// <param name="key">Data key.</param>
        /// <param name="entry">Data to cache.</param>
        /// <param name="utcExpiry">Expiration time (UTC).</param>
        /// <param name="sessionId">The Session identifier, optional.</param>
        /// <param name="metaTags">The meta tags associated with the cached data, optional.</param>
        /// <returns>Returns cached object.</returns>
        protected object Add(string key, object entry, DateTime utcExpiry, string sessionId, string[] metaTags)
        {
            return this.CacheStorageAdapter.Add(key, entry, utcExpiry, sessionId, metaTags);
        }

        /// <summary>
        /// Method sets (updates or adds) data into the cache with specified key and expiration.
        /// </summary>
        /// <param name="key">Data key.</param>
        /// <param name="entry">Data to cache.</param>
        /// <param name="utcExpiry">Expiration time (UTC).</param>
        public override void Set(string key, object entry, DateTime utcExpiry)
        {
            this.TrySet(key, entry, utcExpiry, "");
        }

        /// <summary>
        /// Method sets (updates or adds) data into the cache with specified key and expiration.
        /// </summary>
        /// <param name="key">Data key.</param>
        /// <param name="entry">Data to cache.</param>
        /// <param name="utcExpiry">Expiration time (UTC).</param>
        protected void Set(string key, object entry, DateTime utcExpiry, string sessionId)
        {
            this.TrySet(key, entry, utcExpiry, sessionId, null);
        }

        /// <summary>
        /// Method sets (updates or adds) data into the cache with specified key and expiration.
        /// </summary>
        /// <param name="key">Data key.</param>
        /// <param name="entry">Data to cache.</param>
        /// <param name="utcExpiry">Expiration time (UTC).</param>
        /// <param name="sessionId">The Session identifier, optional.</param>
        /// <param name="metaTags">The meta tags associated with the cached data, optional.</param>
        protected void Set(string key, object entry, DateTime utcExpiry, string sessionId, string[] metaTags)
        {
            this.TrySet(key, entry, utcExpiry, sessionId, metaTags);
        }

        /// <summary>
        /// Method sets (updates or adds) data into the cache with specified key and expiration.
        /// </summary>
        /// <param name="key">Data key.</param>
        /// <param name="entry">Data to cache.</param>
        /// <param name="utcExpiry">Expiration time (UTC).</param>
        /// <param name="sessionId">The Session identifier, optional.</param>
        /// <returns>Returns boolean value indicating success.</returns>
        protected bool TrySet(string key, object entry, DateTime utcExpiry, string sessionId)
        {
            return this.TrySet(key, entry, utcExpiry, sessionId, null);
        }

        /// <summary>
        /// Method sets (updates or adds) data into the cache with specified key and expiration.
        /// </summary>
        /// <param name="key">Data key.</param>
        /// <param name="entry">Data to cache.</param>
        /// <param name="utcExpiry">Expiration time (UTC).</param>
        /// <param name="sessionId">The Session identifier, optional.</param>
        /// <param name="metaTags">The meta tags associated with the cached data, optional.</param>
        /// <returns>Returns boolean value indicating success.</returns>
        protected bool TrySet(string key, object entry, DateTime utcExpiry, string sessionId, string[] metaTags)
        {
            return this.CacheStorageAdapter.TrySet(key, entry, utcExpiry, sessionId, metaTags);
        }

        /// <summary>
        /// Method removes data from the cache using specified key.
        /// </summary>
        /// <param name="key">Data key.</param>
        public override void Remove(string key)
        {
            this.CacheStorageAdapter.Remove(key);
        }

        /// <summary>
        /// Method gets the total count of records in the database instance.
        /// </summary>
        /// <returns>Returns the total count of records in the database instance.</returns>
        public long GetCount()
        {
            return this.CacheStorageAdapter.GetCount();
        }

        /// <summary>
        /// Method removes all records from the database instance.
        /// </summary>
        public void RemoveAll()
        {
            this.CacheStorageAdapter.RemoveAll();
        }

        /// <summary>
        /// Method removes all expired records from the database instance.
        /// </summary>
        public void RemoveExpired()
        {
            this.CacheStorageAdapter.RemoveExpired();
        }

        /// <summary>
        /// Method compacts data in the database.
        /// </summary>
        public void Compact()
        {
            this.CacheStorageAdapter.Compact();
        }

        public void Dispose()
        {
        }
    }
}
